package sr.myserver.commons;

import lombok.extern.slf4j.Slf4j;
import okhttp3.*;

import javax.net.ssl.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * http 工具类
 *
 * @author sirui
 */
@Slf4j
public class OkHttpUtil {
    private static final String HTTPS = "https:";
    private static final int HTTP_OK = 200;

    /**
     * 自定义请求格式（公共）
     *
     * @param request okhttp请求信息定义
     * @return body string字符串，失败返回""
     */
    public static String newNet(Request request) {
        Response response = null;
        OkHttpClient client;
        try {
            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            if (request.url().url().toString().startsWith(HTTPS)) {
                builder.connectTimeout(15, TimeUnit.SECONDS)
                        .readTimeout(15, TimeUnit.SECONDS)
                        .writeTimeout(15, TimeUnit.SECONDS)
                        .sslSocketFactory(SslSocketClient.getSslSocketFactory(), null)
                        .hostnameVerifier(SslSocketClient.getHostnameVerifier());
            }
            client = builder.build();
            response = client.newCall(request).execute();
            int status = response.code();
            if (status == HTTP_OK) {
                String body = response.body().string();
                return body;
            } else if (response.isSuccessful()) {
                log.error("http网络请求非正常响应：" + response.body().string());
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("http网络请求异常信息：" + e.getMessage());
        } finally {
            if (response != null) {
                response.close();
            }
        }
        return "";
    }

    /**
     * GET方式提交表单数据
     *
     * @param url 访问地址
     * @return body string字符串，失败返回""
     */
    public static String newGetForm(String url) {
        Request request = new Request.Builder()
                .url(url)
                .build();
        return newNet(request);
    }

    /**
     * POST方式提交表单数据
     *
     * @param url    访问地址
     * @param params 数据
     * @return body string字符串，失败返回""
     */
    public static String newPostForm(String url, Map<String, String> params) {
        FormBody.Builder builder = new FormBody.Builder();
        if (params != null && params.keySet().size() > 0) {
            for (String key : params.keySet()) {
                builder.add(key, params.get(key));
            }
        }
        Request request = new Request.Builder()
                .url(url)
                .post(builder.build())
                .build();
        return newNet(request);
    }

    /**
     * POST方式提交json格式数据
     *
     * @param url     访问地址
     * @param jsonStr 数据
     * @return body string字符串，失败返回""
     */
    public static String newPostJson(String url, String jsonStr) {
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), jsonStr);
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
        return newNet(request);
    }

    /**
     * POST方式提交xml格式数据
     *
     * @param url    访问地址
     * @param xmlStr 数据
     * @return body string字符串，失败返回""
     */
    public static String newPostXml(String url, String xmlStr) {
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/xml; charset=utf-8"), xmlStr);
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
        return newNet(request);
    }

    public static boolean downFile(String url, String filePath) {
        Request request = new Request.Builder().url(url).build();
        FileOutputStream fos = null;
        Response response = null;
        try {
            OkHttpClient client = new OkHttpClient();
            response = client.newCall(request).execute();
            int status = response.code();
            if (status == HTTP_OK) {
                InputStream is = response.body().byteStream();
                File file = new File(filePath);
                fos = new FileOutputStream(file);
                int len;
                byte[] buf = new byte[2048];
                while ((len = is.read(buf)) != -1) {
                    fos.write(buf, 0, len);
                }
                fos.flush();
                return true;
            } else if (response.isSuccessful()) {
                log.error("http网络请求非正常响应：" + response.body().string());
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("http网络请求异常信息：" + e.getMessage());
        } finally {
            try {
                assert response != null;
                response.close();
            } catch (Exception e) {
            }
            try {
                assert fos != null;
                fos.close();
            } catch (Exception e) {
            }
        }
        return false;
    }

    public static class SslSocketClient {
        public static SSLSocketFactory getSslSocketFactory() {
            try {
                SSLContext sslContext = SSLContext.getInstance("SSL");
                sslContext.init(null, getTrustManager(), new SecureRandom());
                return sslContext.getSocketFactory();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        public static HostnameVerifier getHostnameVerifier() {
            HostnameVerifier hostnameVerifier = new HostnameVerifier() {
                @Override
                public boolean verify(String s, SSLSession sslSession) {
                    return true;
                }
            };
            return hostnameVerifier;
        }

        private static TrustManager[] getTrustManager() {
            return new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(X509Certificate[] chain, String authType) {
                        }

                        @Override
                        public void checkServerTrusted(X509Certificate[] chain, String authType) {
                        }

                        @Override
                        public X509Certificate[] getAcceptedIssuers() {
                            return new X509Certificate[]{};
                        }
                    }
            };
        }
    }
}